﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.Security.Cryptography;

using Microsoft.Exchange.WebServices.Data;

using ExchangeHog.Pop3Client;

namespace ExchangeHog
{
	/// <summary>
	/// Interaction logic for MainWindow.xaml
	/// </summary>
	public partial class MainWindow : Window
	{
		public MainWindow()
		{
			Config = new EHConfig();
			InitializeComponent();
		}

		private void MenuItem_Click(object sender, RoutedEventArgs e)
		{
			MessageBox.Show("ExchangeHog by aam");
		}

		public EHConfig Config { get; set; }

		private void btnGo_Click(object sender, RoutedEventArgs e)
		{
			if (Config == null)
			{
				MessageBox.Show("No configuration is set up", "ExchangeHog", MessageBoxButton.OK, MessageBoxImage.Exclamation);
				return;
			}

			ExchangeService service = new ExchangeService();

			service.Credentials = new System.Net.NetworkCredential(Config.ExchangeUserid, Config.SSExchangePassword);
			service.Url = new Uri(Config.ExchangeUrl);

			//var iv = new ItemView(10);
			//foreach (Item i in service.FindItems(WellKnownFolderName.SentItems, iv))
			//{
			//    PropertySet pset = new PropertySet(BasePropertySet.FirstClassProperties) { ItemSchema.MimeContent };
			//    i.Load(pset);
			//    MessageBody mb = i.Body;
			//}

			foreach (Pop3Config pop3config in Config.Pop3s)
			{
				var ssPassword = new System.Security.SecureString();
				foreach (Char ch in pop3config.Password.ToCharArray())
					ssPassword.AppendChar(ch);

				try
				{
					using (var client = new Pop3Client.Pop3Client(pop3config.Userid, ssPassword, pop3config.Server, pop3config.Port, pop3config.SSL))
					{
						client.Trace += new Action<string>(Console.WriteLine);
						client.Authenticate();
						client.Stat();
						foreach (Pop3ListItem item in client.List())
						{
							System.Net.Mail.MailMessage msgIn = client.RetrieveMailMessage(item);
							//Console.WriteLine("Children.Count: {0}", msgIn.Children.Count);
							//Console.WriteLine("message-id: {0}", msgIn.MessageId);
							Console.WriteLine("subject: {0}", msgIn.Subject);
							Console.WriteLine("Attachments.Count: {0}", msgIn.Attachments.Count);
							//client.Dele(item);	

							EmailMessage msgOut = new EmailMessage(service);
							msgOut.Subject = msgIn.Subject;
							msgOut.Body = msgIn.Body;
							msgOut.Body.BodyType = msgIn.IsBodyHtml ? BodyType.HTML : BodyType.Text;
							msgOut.From = new EmailAddress(msgIn.From.DisplayName, msgIn.From.Address);
							foreach (System.Net.Mail.MailAddress ma in msgIn.To)
								msgOut.ToRecipients.Add(new EmailAddress(ma.DisplayName, ma.Address));
							foreach (System.Net.Mail.Attachment attachment in msgIn.Attachments)
								msgOut.Attachments.AddFileAttachment(attachment.Name, attachment.ContentStream);

							msgOut.Save();
							msgOut.Move(WellKnownFolderName.Inbox);
							msgOut.IsRead = false;
						}
						client.Noop();
						client.Rset();
						client.Quit();
					}
				}
				catch (Exception exception)
				{
					MessageBox.Show("Problem during processing: " + exception, "ExchangeHog", MessageBoxButton.OK, MessageBoxImage.Exclamation);
				}
			}
		}

		private void btnAddNew_Click(object sender, RoutedEventArgs e)
		{
			Pop3Config p3c = new Pop3Config();
			p3c.Server = "xxx.xxx.com";
			p3c.Userid = "xxx@xxx.com";
			p3c.SSL = true;
			p3c.Port = 995;
			p3c.Password = "xxx";
			Config.Pop3s.Add(p3c);
		}

		//
		// Encrypt, Decrypt below are taken from http://www.csharper.net/blog/library_encrypt_and_decrypt_methods_using_tripledes_and_md5.aspx
		//
		public static string Encrypt(string toEncrypt, string key, bool useHashing)
		{
			byte[] keyArray;
			byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);

			if (useHashing)
			{
				MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
				keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
				hashmd5.Clear();
			}
			else
				keyArray = UTF8Encoding.UTF8.GetBytes(key);

			TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
			tdes.Key = keyArray;
			tdes.Mode = CipherMode.ECB;
			tdes.Padding = PaddingMode.PKCS7;

			ICryptoTransform cTransform = tdes.CreateEncryptor();
			byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);

			tdes.Clear();

			return Convert.ToBase64String(resultArray, 0, resultArray.Length);
		}

		public static string Decrypt(string toDecrypt, string key, bool useHashing)
		{
			byte[] keyArray;
			byte[] toEncryptArray = Convert.FromBase64String(toDecrypt);

			if (useHashing)
			{
				MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
				keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
				hashmd5.Clear();
			}
			else
				keyArray = UTF8Encoding.UTF8.GetBytes(key);

			TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
			tdes.Key = keyArray;
			tdes.Mode = CipherMode.ECB;
			tdes.Padding = PaddingMode.PKCS7;

			ICryptoTransform cTransform = tdes.CreateDecryptor();
			byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
			tdes.Clear();

			return UTF8Encoding.UTF8.GetString(resultArray);
		}

		private void OpenCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
			dlg.DefaultExt = ".ehcfg";
			dlg.Filter = "ExchangeHog config file (.ehcfg)|*.ehcfg";
			Nullable<bool> result = dlg.ShowDialog();
			if (result == true)
			{
				string filename = dlg.FileName;
				Config.Load(filename);
			}
		}

		private void SaveAsCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
			dlg.DefaultExt = ".ehcfg";
			dlg.Filter = "ExchangeHog config file (.ehcfg)|*.ehcfg";
			Nullable<bool> result = dlg.ShowDialog();
			if (result == true)
				Config.Save(dlg.FileName);
		}

		private void SaveCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			Config.Save(Config.FileName);
		}

		private void OpenCommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = true;
		}

		private void SaveCommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = Config != null && Config.FileName != null;
		}

		private void SaveAsCommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = Config != null;
		}

		private void PopItemDeleteCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			ListView lv = sender as ListView;
			if (lv != null && lv.SelectedItems != null)
			{
				var selected = new List<Pop3Config>();
				foreach (Pop3Config lvi in lv.SelectedItems)
					selected.Add(lvi);
				foreach (Pop3Config lvi in selected)
					Config.Pop3s.Remove(lvi);
			}
		}

		private void PopItemDeleteCommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = true;
		}

	}

	public class BoolToVisibilityConverter : IValueConverter
	{
		public object Convert(object value, Type targetType,
			object parameter, System.Globalization.CultureInfo culture)
		{
			bool param = bool.Parse(parameter as string);
			bool val = (bool)value;

			return val == param ? Visibility.Visible : Visibility.Hidden;
		}

		public object ConvertBack(object value, Type targetType,
			object parameter, System.Globalization.CultureInfo culture)
		{
			throw new NotImplementedException();
		}
	} // end of BoolToVisibilityConverter

	public static class PasswordHelper
	{
		public static readonly DependencyProperty PasswordProperty =
			DependencyProperty.RegisterAttached("Password", typeof(string), typeof(PasswordHelper), new FrameworkPropertyMetadata(string.Empty, OnPasswordPropertyChanged));

		public static readonly DependencyProperty AttachProperty =
			DependencyProperty.RegisterAttached("Attach", typeof(bool), typeof(PasswordHelper), new PropertyMetadata(false, Attach));
		
		private static readonly DependencyProperty IsUpdatingProperty =
		   DependencyProperty.RegisterAttached("IsUpdating", typeof(bool), typeof(PasswordHelper));

		public static void SetAttach(DependencyObject dp, bool value) { dp.SetValue(AttachProperty, value); }
		public static bool GetAttach(DependencyObject dp) { return (bool)dp.GetValue(AttachProperty); }

		public static string GetPassword(DependencyObject dp) { return (string)dp.GetValue(PasswordProperty); }
		public static void SetPassword(DependencyObject dp, string value) { dp.SetValue(PasswordProperty, value); }

		private static bool GetIsUpdating(DependencyObject dp) { return (bool)dp.GetValue(IsUpdatingProperty); }
		private static void SetIsUpdating(DependencyObject dp, bool value) { dp.SetValue(IsUpdatingProperty, value); }

		private static void OnPasswordPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
		{
			PasswordBox passwordBox = sender as PasswordBox;
			passwordBox.PasswordChanged -= PasswordChanged;

			if (!(bool)GetIsUpdating(passwordBox))
				passwordBox.Password = (string)e.NewValue;
			passwordBox.PasswordChanged += PasswordChanged;
		}

		private static void Attach(DependencyObject sender, DependencyPropertyChangedEventArgs e)
		{
			PasswordBox passwordBox = sender as PasswordBox;
			if (passwordBox != null)
			{
				if ((bool)e.OldValue)
					passwordBox.PasswordChanged -= PasswordChanged;

				if ((bool)e.NewValue)
					passwordBox.PasswordChanged += PasswordChanged;
			}
		}

		private static void PasswordChanged(object sender, RoutedEventArgs e)
		{
			PasswordBox passwordBox = sender as PasswordBox;
			SetIsUpdating(passwordBox, true);
			SetPassword(passwordBox, passwordBox.Password);
			SetIsUpdating(passwordBox, false);
		}
	} // end of PasswordHelper
}
